home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / ReadMATLABFile.c < prev    next >
Text File  |  1995-07-20  |  12KB  |  419 lines

  1. /*
  2. ReadMATLABFile.c - load/save a matrix from/to a MATLAB data file.
  3. These functions allow any C program to read and write MATLAB data files.
  4.  
  5. int SaveMatDoubles(FILE *f,char *name,long rows,long cols
  6.     ,double *real,double *imag);            // write doubles as 8-byte DOUBLES
  7. int SaveMatShorts(FILE *f,char *name,long rows,long cols
  8.     ,short *real,short *imag);                // write shorts as shorts
  9. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  10.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  11. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  12.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  13. int LoadNamedMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  14.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  15. int LoadNamedMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  16.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  17.  
  18. All the routines assume an open file, and return an error if they hit end of
  19. file. The SaveXXX routines append a matrix to the existing file. The LoadNextXXX
  20. routines read the next matrix from the file, advancing the file pointer.
  21. SaveXXX and LoadNextXXX can be called repeatedly until they fail (e.g. end of
  22. file is reached). The LoadNamedXXX routines first rewind the file and then scan
  23. it until they find a matrix whose name matches that supplied, or end of file is
  24. reached. The file pointer is left at the end of that matrix. Calling LoadNameXXX
  25. repeatedly will read the same matrix every time: the first instance of the named
  26. matrix.
  27.  
  28. The LoadXXX and SaveXXX routines return 0 if successful and a positive nonzero
  29. integer if they fail.  The two array pointers will be NULL after calling LoadXXX
  30. unless they are loaded. The second (imaginary) pointer will be NULL unless the
  31. matrix was complex. Similarly, when you call SaveXXX you indicate a real matrix
  32. by supplying a NULL second pointer.
  33.  
  34. There is a slight asymmetry here that you should be aware of. SaveMatShorts()
  35. produces a (compact) MATLAB file made up of shorts, but the
  36. LoadXXXMatIntoShorts() will only read a (big) MATLAB file made up of 8-byte
  37. doubles. So you won't always be able to read from C the file you wrote from C.
  38. The reason for this is that while the MATLAB "Load" command supports all the
  39. MATLAB file formats, the MATLAB "Save" command has no provision for specifying
  40. (binary) file formats and thus always uses format type 0, 8-byte short doubles,
  41. so I didn't bother to implement any routines to read any other format. (It would
  42. be easy to add this capability, if it were needed.)
  43.  
  44. EXAMPLES:
  45. This example loads the first two matrices from a MATLAB file:
  46.  
  47.     FILE *f;
  48.     char name[64];
  49.     long rows,cols;
  50.     double *xr,*xi;
  51.     short *mr,*mi;
  52.     int error;
  53.     f = fopen("foo.mat","rb");
  54.     error=LoadNextMatIntoDoubles(f,name,&rows,&cols,&xr,&xi);
  55.      error=LoadNextMatIntoShorts(f,name,&rows,&cols,&mr,&mi);
  56.     fclose(f);
  57.     free(xr);
  58.     free(xi);
  59.     free(mr);
  60.     free(mi);
  61.  
  62. Alternatively, you can read a specific matrix, by name, from the file:
  63.  
  64.     error=LoadNamedMatIntoDoubles(f,"Put name here",&rows,&cols,&xr,&xi);
  65.      error=LoadNamedMatIntoShorts(f,"Put name here",&rows,&cols,&mr,&mi);
  66.  
  67. This example creates a MATLAB file containing four matrices:
  68.  
  69.     FILE *fp;
  70.     double xyz[1000],ar[1000],ai[1000];
  71.     short m[100],n[100];
  72.     fp = fopen("bar.mat","wb");
  73.     SetFileInfo("bar.mat",'MATW','MATL');
  74.     error=SaveMatDoubles(fp,"xyz",2,3,xyz,NULL);    // real
  75.     error=SaveMatShorts(fp,"m",2,3,m,NULL);            // real
  76.     error=SaveMatDoubles(fp,"a",5,5,ar,ai);            // complex
  77.     error=SaveMatShorts(fp,"mc",2,3,m,n);            // complex
  78.     fclose(fp);
  79.  
  80.  
  81. HISTORY:
  82. 11-3-86 J.N. Little wrote loadmat.c and savemat.c
  83.  
  84. [14-Feb-91] jmb -- Added support for MPW C 3.x and THINK C.
  85.  
  86. 1/4/93    dgp Renamed to MatLab.c. DOUBLE is now used soley within the new
  87. WriteXXX and ReadXXX subroutines. C users now only deal with double and short
  88. arrays; necessary conversions are done behind the scenes. double is faster and
  89. more convenient for Macintosh programming than the 8-byte short double used in
  90. the MATLAB files. Added support for file format 3: signed short ints. Omitted
  91. the imagf flag since it's redundant. Omitted the type argument by supplying
  92. several user-callable front ends, each tailored to a particular number type.
  93.  
  94. 2/93 dgp Renamed to ReadMatLabFile.c
  95.  
  96. 6/22-25/93 jas & dgp wrote LoadNamedMat. Renamed LoadMatShorts and
  97. LoadMatDoubles to LoadNextMatIntoShorts and LoadNextMatIntoDoubles. Added
  98. LoadNamedMatIntoShorts and LoadNamedMatIntoDoubles.
  99.  
  100. 12/93 dgp Renamed to ReadMATLABFile.c
  101.  
  102. 7/28/94 dgp added support for Metrowerks CodeWarrior C compiler.
  103.  
  104. 6/8/95 dgp Made sure that the MATLAB struct "Fmatrix" is always native aligned.
  105. */
  106. #include "VideoToolbox.h"
  107.  
  108. double *ReadDoubles(FILE *f,long elements,char *name);
  109. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name);
  110. int WriteDoubles(FILE *f,long elements,char *name,double *d);
  111. int WriteShorts(FILE *f,long elements,char *name,short *d);
  112. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type);
  113. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  114.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  115. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  116.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  117.  
  118. #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
  119.     #pragma options align=native
  120. #endif
  121.  
  122. typedef struct {
  123.      long type;        /* type */
  124.      long rows;        /* row dimension */
  125.      long cols;        /* column dimension */
  126.      long imagf;    /* flag indicating imag part */
  127.      long namlen;    /* name length (including NULL) */
  128. } Fmatrix;
  129.  
  130. #if PRAGMA_ALIGN_SUPPORTED || __MWERKS__
  131.     #pragma options align=reset
  132. #endif
  133.  
  134. /* From cmex.h */
  135. /*
  136. MATLAB files with number format 0 use 8-byte floating point numbers, which
  137. we'll call DOUBLE. It's defined in VideoToolbox.h
  138. */
  139.  
  140. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  141.     ,double **real,double **imag)
  142. {
  143.     long fileType,desiredNumberType=0;
  144.     
  145.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  146.         ,&fileType,desiredNumberType);
  147. }
  148.     
  149. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  150.     ,short **real,short **imag)
  151. {
  152.     long fileType,desiredNumberType=3;
  153.     
  154.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  155.         ,&fileType,desiredNumberType);
  156. }
  157.  
  158. int LoadNamedMatIntoDoubles(FILE *f,const char *name,long *rows,long *cols
  159.     ,double **real,double **imag)
  160. {
  161.     long fileType,desiredNumberType=0;
  162.     
  163.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  164.         ,&fileType,desiredNumberType);
  165. }
  166.     
  167. int LoadNamedMatIntoShorts(FILE *f,const char *name,long *rows,long *cols
  168.     ,short **real,short **imag)
  169. {
  170.     long fileType,desiredNumberType=3;
  171.     
  172.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  173.         ,&fileType,desiredNumberType);
  174. }
  175.  
  176. int SaveMatDoubles(FILE *f,char *name,long rows,long cols,double *real,double *imag)
  177. {
  178.     return SaveMat(f,name,rows,cols,real,imag,0);
  179. }
  180.  
  181. int SaveMatShorts(FILE *f,char *name,long rows,long cols,short *real,short *imag)
  182. {
  183.     return SaveMat(f,name,rows,cols,real,imag,30);
  184. }
  185.     
  186. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  187.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  188. {
  189.     char curname[100];
  190.     int error;
  191.     
  192.     rewind(f);
  193.     while(1){
  194.         error=LoadNextMat(f,curname,rows,cols,real,imag,fileType,desiredNumberType);
  195.         if(error)return error;
  196.         if(strcmp(curname,name)==0)break;
  197.         if(*real!=NULL){
  198.             free(*real);
  199.             *real=NULL;
  200.         }
  201.         if(*imag!=NULL){
  202.             free(*imag);
  203.             *imag=NULL;
  204.         }
  205.     }
  206.     return 0;
  207. }
  208.  
  209. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  210.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  211. {
  212.     Fmatrix    x;
  213.     long elements,namlen,numberFormat;
  214.     
  215.     *real=*imag=NULL;
  216.     name[0]=0;
  217.     if(feof(f))return 1;
  218.  
  219.     /* Get Fmatrix structure from file */
  220.     if (fread((char *)&x,sizeof(Fmatrix),1,f) != 1) return 2;
  221.     *fileType = x.type;
  222.     *rows = x.rows;
  223.     *cols = x.cols;
  224.     namlen = x.namlen;
  225.     elements = x.rows * x.cols;
  226.  
  227.     if(x.type/1000!=1)return 3;        /* not Macintosh-compatible binary format */
  228.     if(x.type/100%10!=0)return 4;    /* transposed */
  229.     numberFormat=x.type/10%10;
  230.     if(numberFormat!=0)return 5;    /* not 8-byte doubles */
  231.  
  232.     /* Get matrix name from file */
  233.     if (fread(name,sizeof(char),namlen,f) != namlen) return 6;
  234.     
  235.     /* Get Real part of matrix from file */
  236.     switch(desiredNumberType){
  237.     case 0:
  238.         *real=ReadDoubles(f,elements,name);
  239.         break;
  240.     case 3:
  241.         *real=ReadDoublesIntoShorts(f,elements,name);
  242.         break;
  243.     default:
  244.         *real=NULL;
  245.     }
  246.     if(*real==NULL)return 7;
  247.  
  248.     /* Get Imag part of matrix from file, if it exists */
  249.     if (x.imagf) {
  250.         switch(desiredNumberType){
  251.         case 0:
  252.             *imag=ReadDoubles(f,elements,name);
  253.             break;
  254.         case 3:
  255.             *imag=ReadDoublesIntoShorts(f,elements,name);
  256.             break;
  257.         }
  258.         if(*imag==NULL){
  259.             free(*real);
  260.             *real=NULL;
  261.             return 8;
  262.         }
  263.     }
  264.     return 0;
  265. }
  266.  
  267. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type)
  268. {
  269.     Fmatrix    x;
  270.     long elements;
  271.     int error;
  272.     int fileFormat;
  273.     
  274.     type%=100;    /* not transposed */
  275.     type+=1000;    /* indicate Macintosh-compatible binary format */
  276.     x.type = type;
  277.     x.rows = rows;
  278.     x.cols = cols;
  279.     if(imag==NULL)x.imagf=0;
  280.     else x.imagf=1;
  281.     x.namlen = strlen(name) + 1;
  282.     elements = x.rows * x.cols;
  283.  
  284.     if(x.type/1000!=1)return 9;        /* not Macintosh-compatible binary format */
  285.     if(x.type/100%10!=0)return 10;    /* transposed */
  286.     fileFormat=x.type/10%10;
  287.     if(fileFormat!=0 && fileFormat!=3)return 11; /* neither 8-byte double, nor short */
  288.  
  289.     fwrite(&x,sizeof(Fmatrix),1,f);
  290.     fwrite(name,sizeof(char),(long)x.namlen,f);
  291.     switch(fileFormat){
  292.     case 0:
  293.         error=WriteDoubles(f,elements,name,real);
  294.         break;
  295.     case 3:
  296.         error=WriteShorts(f,elements,name,real);
  297.         break;
  298.     default:
  299.         error=1;
  300.     }
  301.     if(error)return 12;
  302.     if (imag!=NULL) {
  303.         switch(fileFormat){
  304.         case 0:
  305.             error=WriteDoubles(f,elements,name,imag);
  306.             break;
  307.         case 3:
  308.             error=WriteShorts(f,elements,name,imag);
  309.             break;
  310.         default:
  311.             error=1;
  312.         }
  313.         if(error)return 13;
  314.     }
  315.     return 0;
  316. }
  317.  
  318. /* Reads DOUBLES (8-byte doubles) into doubles */
  319. double *ReadDoubles(FILE *f,long elements,char *name)
  320. {
  321.     DOUBLE *D;
  322.     double *d;
  323.     long i,n,j;
  324.     const dSize=2048/sizeof(DOUBLE);    /* Can be whatever you want. Bigger is faster. */
  325.     
  326.     assert(sizeof(DOUBLE)==8);
  327.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  328.     if(D==NULL){
  329.         printf("\nError: not enough room for buffer\n");
  330.         return NULL;
  331.     }
  332.     if (!(d = (double *)malloc(elements*sizeof(*d)))) {
  333.         printf("\nError: Variable %s too big to load\n",name);
  334.         return NULL;
  335.     }
  336.     for(i=0;i<elements;){
  337.         if(dSize<elements-i)n=dSize;
  338.         else n=elements-i;
  339.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  340.             free(d);
  341.             free(D);
  342.             return NULL;
  343.         }
  344.         for(j=0;j<n;j++)d[i++]=D[j];    /* convert DOUBLE to double */
  345.     }
  346.     free(D);
  347.     return d;
  348. }
  349.  
  350. /* Reads DOUBLES (8-byte short doubles) into shorts */
  351. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name)
  352. {
  353.     DOUBLE *D;
  354.     short *d;
  355.     long i,n,j;
  356.     const dSize=2048/sizeof(DOUBLE);    /* Can be whatever you want. Bigger is faster. */
  357.     
  358.     assert(sizeof(DOUBLE)==8);
  359.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  360.     if(D==NULL){
  361.         printf("\nError: not enough room for buffer\n");
  362.         return NULL;
  363.     }
  364.     if (!(d = (short *)malloc(elements*sizeof(*d)))) {
  365.         printf("\nError: Variable %s too big to load\n",name);
  366.         return NULL;
  367.     }
  368.     for(i=0;i<elements;){
  369.         if(dSize<elements-i)n=dSize;
  370.         else n=elements-i;
  371.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  372.             free(d);
  373.             free(D);
  374.             return NULL;
  375.         }
  376.         for(j=0;j<n;j++)d[i++]=D[j];    /* convert DOUBLE to short */
  377.     }
  378.     free(D);
  379.     return d;
  380. }
  381.  
  382. /* Writes doubles as DOUBLES (8-byte short doubles) */
  383. int WriteDoubles(FILE *f,long elements,char *name,double *d)
  384. {
  385.     DOUBLE *D;
  386.     long i,n,j;
  387.     const dSize=2048/sizeof(DOUBLE);    /* Can be whatever you want. Bigger is faster. */
  388.     
  389.     name;    /* prevent "unused argument" warning */
  390.     assert(sizeof(DOUBLE)==8);
  391.     if (d==NULL) return 14;
  392.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  393.     if(D==NULL){
  394.         printf("\nError: not enough room for buffer\n");
  395.         return 15;
  396.     }
  397.     for(i=0;i<elements;){
  398.         if(dSize<elements-i)n=dSize;
  399.         else n=elements-i;
  400.         for(j=0;j<n;j++)D[j]=d[i++];    /* convert double to DOUBLE */
  401.         if(fwrite(D,sizeof(DOUBLE),n,f) != n) {
  402.             free(D);
  403.             return 16;
  404.         }
  405.     }
  406.     free(D);
  407.     return 0;
  408. }
  409.  
  410. /* Writes shorts as shorts */
  411. int WriteShorts(FILE *f,long elements,char *name,short *d)
  412. {
  413.     name;    /* prevent "unused argument" warning */
  414.     assert(sizeof(short)==2);
  415.     if (d==NULL) return 17;
  416.     if(fwrite(d,sizeof(short),elements,f) != elements) return 18;
  417.     return 0;
  418. }
  419.